#!/usr/bin/python3
# coding: utf-8
#
# A simple indicator applet displaying cpu and memory information
#
# Author: Alex Eftimie <alex@eftimie.ro>
# Fork Author: fossfreedom <foss.freedom@gmail.com>
# Original Homepage: http://launchpad.net/indicator-sysmonitor
# Fork Homepage: https://github.com/fossfreedom/indicator-sysmonitor
# License: GPL v3
#
import logging
import os
import sys
import tempfile
from argparse import ArgumentParser
from gettext import gettext as _
from gettext import bindtextdomain, textdomain
from threading import Event

import gi
try:
    gi.require_version('AyatanaAppIndicator3', '0.1')
    from gi.repository import AyatanaAppIndicator3 as appindicator
except ValueError:
    gi.require_version('AppIndicator3', '0.1')
    from gi.repository import AppIndicator3 as appindicator

from gi.repository import GLib, Gtk

from preferences import __version__, Preferences
from sensors import SensorManager

textdomain("indicator-sysmonitor")
bindtextdomain("indicator-sysmonitor", "./lang")

logging.basicConfig(level=logging.INFO)

HELP_MSG = """<span underline="single" size="x-large">{title}</span>

{introduction}

{basic}
• cpu: {cpu_desc}
• mem: {mem_desc}
• bat<i>%d</i>: {bat_desc}
• net: {net_desc}
• upordown: {upordown_desc}
• publicip: {publicip_desc}

{compose}
• fs//<i>mount-point</i> : {fs_desc}

<big>{example}</big>
CPU {{cpu}} | MEM {{mem}} | root {{fs///}}
""".format(
    title=_("Help Page"),
    introduction=_("The sensors are the names of the devices from which you want to retrive information. They must be placed between brackets."),
    basic=_("The basics are:"),
    cpu_desc=_("It shows the average of CPU usage."),
    mem_desc=_("It shows the physical memory in use."),
    bat_desc=_("It shows the available battery which id is %d."),
    net_desc=_("It shows the amount of data you are downloading and uploading through your network."),
    upordown_desc=_("It shows whether your internet connection is up or down (the sensor is refreshed every 10 seconds)."),
    publicip_desc=_("It shows your public IP address (the sensor is refreshed every 10 minutes)."),
    compose=_("Also there are the following sensors that are composed with two parts divided by two slashes."),
    fs_desc=_("Show available space in the file system."),
    example=_("Example:"))


class IndicatorSysmonitor(object):
    SENSORS_DISABLED = False

    def __init__(self):
        self._preferences_dialog = None
        self._help_dialog = None

        fn, self.tindicator = tempfile.mkstemp(suffix=".svg")

        with open(self.tindicator, "w") as f:
            svg = '<?xml version="1.0" encoding="UTF-8" \
                        standalone="no"?><svg id="empty" xmlns="http://www.w3.org/2000/svg" \
                        height="22" width="1" version="1.0" \
                        xmlns:xlink="http://www.w3.org/1999/xlink"></svg>'
            f.write(svg)
            f.close()

        self.ind = appindicator.Indicator.new("indicator-sysmonitor", self.tindicator, \
                                              appindicator.IndicatorCategory.SYSTEM_SERVICES)
        self.ind.set_ordering_index(0)

        self.ind.set_status(appindicator.IndicatorStatus.ACTIVE)
        self.ind.set_label("Init...", "")

        self._create_menu()

        self.alive = Event()
        self.alive.set()

        self.sensor_mgr = SensorManager()
        self.load_settings()

    def _create_menu(self):
        """Creates the main menu and shows it."""
        # create menu {{{
        menu = Gtk.Menu()
        # add System Monitor menu item
        full_sysmon = Gtk.MenuItem(label='System Monitor')
        full_sysmon.connect('activate', self.on_full_sysmon_activated)
        menu.add(full_sysmon)
        menu.add(Gtk.SeparatorMenuItem())

        # add preferences menu item
        pref_menu = Gtk.MenuItem(label='Preferences')
        pref_menu.connect('activate', self.on_preferences_activated)
        menu.add(pref_menu)

        # add help menu item
        help_menu = Gtk.MenuItem(label='Help')
        help_menu.connect('activate', self._on_help)
        menu.add(help_menu)

        # add preference menu item
        exit_menu = Gtk.MenuItem(label='Quit')
        exit_menu.connect('activate', self.on_exit)
        menu.add(exit_menu)

        menu.show_all()
        self.ind.set_menu(menu)
        logging.info("Menu shown")
        # }}} menu done!

    def update_indicator_guide(self):

        guide = self.sensor_mgr.get_guide()

        self.ind.set_property("label-guide", guide)

    def update(self, data):
        # data is the dict of all sensors and their values
        # { name, label }

        # look through data and find out if there are any icons to be set
        for sensor in data:
            test_str = data[sensor].lower()
            if "use_icon" in test_str:
                path = data[sensor].split(":")[1]
                self.ind.set_icon_full(path, "")
                # now strip the icon output from data so that it is not displayed
                remaining = test_str.split("use_icon")[0].strip()
                if not remaining:
                    remaining = " "

                data[sensor] = remaining

            if "clear_icon" in test_str:
                self.ind.set_icon_full(self.tindicator, "")

                remaining = test_str.split("clear_icon")[0].strip()
                if not remaining:
                    remaining = " "

                data[sensor] = remaining

        label = self.sensor_mgr.get_label(data)

        self.ind.set_label(label.strip(), "")
        self.ind.set_title(label.strip())

    def load_settings(self):

        self.sensor_mgr.load_settings()
        self.sensor_mgr.initiate_fetcher(self)
        self.update_indicator_guide()

    # @staticmethod
    def save_settings(self):
        self.sensor_mgr.save_settings()

    def update_settings(self):
        self.sensor_mgr.initiate_fetcher(self)

    # actions raised from menu
    def on_preferences_activated(self, event=None):
        """Raises the preferences dialog. If it's already open, it's
        focused"""
        if self._preferences_dialog is not None:
            self._preferences_dialog.present()
            return

        self._preferences_dialog = Preferences(self)
        self._preferences_dialog.run()
        self._preferences_dialog = None

    def on_full_sysmon_activated(self, event=None):
        os.system('gnome-system-monitor &')

    def on_exit(self, event=None, data=None):
        """Action call when the main programs is closed."""
        # cleanup temporary indicator icon
        os.remove(self.tindicator)
        # close the open dialogs
        if self._help_dialog is not None:
            self._help_dialog.destroy()

        if self._preferences_dialog is not None:
            self._preferences_dialog.destroy()

        logging.info("Terminated")
        self.alive.clear()  # DM: why bother with Event() ???

        try:
            Gtk.main_quit()
        except RuntimeError:
            pass

    def _on_help(self, event=None, data=None):
        """Raise a dialog with info about the app."""
        if self._help_dialog is not None:
            self._help_dialog.present()
            return

        self._help_dialog = Gtk.MessageDialog(
            parent=None, destroy_with_parent=True, text=Gtk.MessageType.INFO,
            buttons=Gtk.ButtonsType.OK)

        self._help_dialog.set_title(_("Help"))
        self._help_dialog.set_markup(HELP_MSG)
        self._help_dialog.run()
        self._help_dialog.destroy()
        self._help_dialog = None

if __name__ == "__main__":
    parser = ArgumentParser()
    parser.add_argument(
        "--config",
        default=None,
        help="Use custom config file."
        )
    parser.add_argument(
        "--version",
        default=False,
        action='store_true',
        help='Show version and exit.'
        )

    options = parser.parse_args()

    if options.version:
        print(__version__)
        exit(0)

    logging.info("start")
    if options.config:
        if not os.path.exists(options.config):
            logging.error(_("{} does not exist!").format(options.config))
            sys.exit(-1)
        logging.info(_("Using config file: {}").format(options.config))
        SensorManager.SETTINGS_FILE = options.config

    if not os.path.exists(SensorManager.SETTINGS_FILE):
        sensor_mgr = SensorManager()
        sensor_mgr.save_settings()

    # setup an instance with config
    app = IndicatorSysmonitor()
    try:
        Gtk.main()
    except KeyboardInterrupt:
        app.on_exit()
